package com.maze.game.board
{
	import com.maze.game.factory.BaseFactory;
	import com.maze.game.factory.LevelFactory;
	import com.maze.game.model.Level;
	import com.maze.game.model.base.Base;
	import com.maze.game.model.base.BaseEvent;
	import com.maze.game.model.base.BaseExit;
	import com.maze.game.model.base.BaseStart;
	import com.maze.game.model.base.BaseType;
	
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.filters.DropShadowFilter;
	import flash.geom.Point;
	
	public class Board extends Sprite
	{
		public var boardWidth:uint = 400;
		public var boardHeight:uint = 400;
		private var cols:uint = 10;
		private var rows:uint = 10;
		private var data:Array;

		private var _baseWidth:uint;
		private function set baseWidth(value:uint):void { _baseWidth = value; }
		private function get baseWidth():uint { return _baseWidth; }
		
		private var _baseHeight:uint;
		private function set baseHeight(value:uint):void { _baseHeight = value; }
		private function get baseHeight():uint { return _baseHeight; }
		
		private var _editable:Boolean = false;
		public function set editable(value:Boolean):void
		{
			_editable = value;
			setEditableMode();
		}
		public function get editable():Boolean { return _editable; }

		private var basesLayer:Sprite;
		private var pathLayer:Sprite;
		private var boardSolution:BoardSolution;
		
		public function Board()
		{
			super();
			var level:Level = LevelFactory.getInstance().getLevel1();
			data = level.data;
			cols = data[0].length;
			rows = data.length;
			baseWidth = level.boardWidth / cols;
			baseHeight = level.boardHeight / rows;
			boardWidth = baseWidth * cols;
			boardHeight = baseHeight * rows;
			BaseFactory.getInstance().baseWidth = baseWidth;
			BaseFactory.getInstance().baseHeight = baseHeight;
			createBoard();
		}
		
		private function createBoard():void
		{
			graphics.clear();
			graphics.lineStyle(2,0x222222);
			graphics.beginFill(0x555555);
			graphics.drawRect(0,0,boardWidth,boardHeight);
			graphics.endFill();
			var colX:uint = baseWidth;
			graphics.lineStyle(1,0x999999);
			for(var col:uint = 0; col<cols; col++)
			{
				graphics.moveTo(colX,0);
				graphics.lineTo(colX,boardHeight);
				colX += baseWidth;
			}
			var rowY:uint = baseHeight;
			for(var row:uint = 0; row<rows; row++)
			{
				graphics.moveTo(0,rowY);
				graphics.lineTo(boardWidth,rowY);
				rowY += baseHeight;
			}
			var filterD:DropShadowFilter = new DropShadowFilter(0, 60, 0x000000, .5, 40, 30, 1, 2, false, false, false);
			filters = [filterD];
			fillBoard();
		}
		
		private function fillBoard():void
		{
			basesLayer = new Sprite();
			addChild(basesLayer);
			var baseType:uint;
			var base:Base;
			for(var row:uint = 0; row<data.length; row++)
			{
				for(var col:uint = 0; col<data[row].length; col++)
				{
					baseType = data[row][col];
					base = BaseFactory.getInstance().getBase(baseType);
					base.editable = editable;
					base.row = row;
					base.col = col;
					base.addEventListener(BaseEvent.TYPE_CHANGED, dataChanged, false, 0, true);
					basesLayer.addChild(base);
					base.x = col*baseWidth;
					base.y = row*baseHeight;
				}
			}
		}

		private function dataChanged(evt:BaseEvent):void
		{
			var base:Base = evt.currentTarget as Base;
			data[base.row][base.col] = base.type;
			if(pathLayer && contains(pathLayer))
				removeChild(pathLayer);
			drawSolution();
		}
		
		public function drawSolution():void
		{
			if(pathLayer && contains(pathLayer))
				removeChild(pathLayer);
			boardSolution = new BoardSolution(data);
			var paths:Vector.<Point> = boardSolution.solutions;
			pathLayer = new Sprite();
			addChild(pathLayer);
			pathLayer.mouseEnabled = false;
			pathLayer.mouseChildren = false;
			for each(var step:Point in paths)
			{
				drawPoint(step, 0x00ff55);
			}
		}
		
		private function drawPoint(point:Point, color:uint = 0xffffff):void
		{
			var base:Base = BaseFactory.getInstance().getColorPoint(color);
			pathLayer.addChild(base);
			base.x = point.x*baseWidth;
			base.y = point.y*baseHeight;
		}
		
		private function setEditableMode():void
		{
			if(basesLayer==null) return;
			var base:Base;
			for (var i:uint = 0; i<basesLayer.numChildren; i++)
			{
				base = basesLayer.getChildAt(i) as Base;
				base.editable = editable;
			}
		}
		
		public function getWallOnly():Sprite
		{
			var walls:Sprite = new Sprite();
			var baseType:uint;
			var base:Base;
			for(var row:uint = 0; row<data.length; row++)
			{
				for(var col:uint = 0; col<data[row].length; col++)
				{
					baseType = data[row][col];
					if(baseType == BaseType.WALL)
					{
						base = BaseFactory.getInstance().getBase(baseType);
						base.row = row;
						base.col = col;
						walls.addChild(base);
						base.x = col*baseWidth;
						base.y = row*baseHeight;
					}
				}
			}
			return walls;
		}
		
		public function getBaseExit():BaseExit
		{
			var baseType:uint;
			var baseExit:BaseExit;
			for(var i:uint = 0; i<basesLayer.numChildren; i++)
			{
				var base:Base = basesLayer.getChildAt(i) as Base;
				if(base.type == BaseType.EXIT)
				{
					baseExit = base as BaseExit;
				}
			}
			return baseExit;
		}

		public function getBaseStart():BaseStart
		{
			var baseType:uint;
			var baseStart:BaseStart;
			for(var i:uint = 0; i<basesLayer.numChildren; i++)
			{
				var base:Base = basesLayer.getChildAt(i) as Base;
				if(base.type == BaseType.START)
				{
					baseStart = base as BaseStart;
				}
			}
			return baseStart;
		}
	}
}